package org.mx.dal.config;

import org.mx.dal.service.EntityManagerService;
import org.mx.dal.service.GeneralAccessor;
import org.mx.dal.service.GeneralDictAccessor;
import org.mx.dal.service.JdbcBatchAccessor;
import org.mx.dal.service.impl.GeneralAccessorImpl;
import org.mx.dal.service.impl.GeneralDictAccessorImpl;
import org.mx.dal.service.impl.JdbcBatchAccessorImpl;
import org.mx.dbcp.MyDbcp2DataSourceFactoryUtil;
import org.mx.spring.session.SessionDataStore;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.Primary;
import org.springframework.core.env.Environment;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.Database;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

/**
 * 基于Hibernate的DAL基础实现，从RDB继承而来。
 *
 * @author : john.peng date : 2017/10/7
 * @see DalConfig
 */
@Import(DalRdbConfig.class)
@EnableTransactionManagement
public class DalHibernateConfig {
	/**
	 * 创建基于JdbcTemplate和事务的JDBC批量数据操作访问器
	 *
	 * @param jdbcTemplate JdbcTemplate
	 * @return JdbcBatchAccessor
	 */
	@Bean(name = "jdbcBatchAccessor")
	public JdbcBatchAccessor jdbcBatchAccessor(JdbcTemplate jdbcTemplate) {
		return new JdbcBatchAccessorImpl(jdbcTemplate);
	}

	/**
	 * 创建一个EntityManagerFactoryBean对象
	 * @param env Spring IoC环境
	 * @param util 数据库连接池工厂集合，可以根据配置名访问
	 * @param dbname 数据库配置名称
	 * @param jpaname jpa配置名称
	 * @return EntityManagerFactoryBean对象
	 */
	public static LocalContainerEntityManagerFactoryBean createEntityManagerFactoryBean(Environment env,
			MyDbcp2DataSourceFactoryUtil util, String dbname, String jpaname) {
		HibernateJpaVendorAdapter adapter = new HibernateJpaVendorAdapter();
		JpaConfigBean jpaConfigBean = new JpaConfigBean(env, jpaname);
		adapter.setDatabase(Database.valueOf(jpaConfigBean.getJpaDatabase()));
		adapter.setDatabasePlatform(jpaConfigBean.getJpaDatabasePlatform());
		adapter.setGenerateDdl(jpaConfigBean.isGenerateDDL());
		adapter.setShowSql(jpaConfigBean.isShowSQL());
		adapter.setPrepareConnection(true);

		LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();
		emf.setDataSource(util.getDataSource(dbname));
		emf.setPersistenceUnitName(jpaConfigBean.getUnitName());
		emf.setPackagesToScan(jpaConfigBean.getJpaEntityPackages());
		emf.setJpaVendorAdapter(adapter);
		return emf;
	}

	/**
	 * 创建实体管理器工厂Bean
	 *
	 * @param env       Spring IoC环境
	 * @param util		数据库连接池工厂集合，可以根据配置名访问
	 * @return 实体管理器工厂Bean
	 */
	@Bean("entityManagerFactory")
	@Primary
	public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean(Environment env,
			MyDbcp2DataSourceFactoryUtil util) {
		return createEntityManagerFactoryBean(env, util, "db", "jpa");
	}

	/**
	 * 创建事务管理器
	 *
	 * @param containerEntityManagerFactoryBean 实体管理器工厂Bean
	 * @return 事务管理器
	 */
	@Bean("transactionManager")
	@Primary
	public PlatformTransactionManager transactionManager(
			@Qualifier("entityManagerFactory") LocalContainerEntityManagerFactoryBean containerEntityManagerFactoryBean) {
		return new JpaTransactionManager(containerEntityManagerFactoryBean.getObject());
	}

	/**
	 * 创建基于JPA的数据对象Accessor
	 * 
	 * @param entityManagerService 实体管理器服务对象
	 * @param sessionDataStore 会话数据存储
	 * @return Accessor
	 */
	@Bean(name = "generalAccessorJpa")
	public GeneralAccessor generalAccessorJpa(
			@Qualifier("entityManagerService") EntityManagerService entityManagerService,
			SessionDataStore sessionDataStore) {
		return new GeneralAccessorImpl(entityManagerService, sessionDataStore);
	}

	/**
	 * 创建基于JPA的字典对象Accessor
	 * 
	 * @param entityManagerService 实体管理器服务对象
	 * @param sessionDataStore 会话数据存储
	 * @return Accessor
	 */
	@Bean(name = "generalDictAccessorJpa")
	public GeneralDictAccessor generalDictAccessorJpa(
			@Qualifier("entityManagerService") EntityManagerService entityManagerService,
			SessionDataStore sessionDataStore) {
		return new GeneralDictAccessorImpl(entityManagerService, sessionDataStore);
	}

	/**
	 * 创建一个通用的数据访问器
	 *
	 * @param context Spring IoC上下文
	 * @return 数据访问器
	 */
	@Bean(name = "generalAccessor")
	public GeneralAccessor generalAccessor(ApplicationContext context) {
		return context.getBean("generalAccessorJpa", GeneralAccessor.class);
	}

	/**
	 * 创建一个通用的字典数据访问器
	 *
	 * @param context Spring IoC上下文
	 * @return 数据访问器
	 */
	@Bean(name = "generalDictAccessor")
	public GeneralDictAccessor generalDictAccessor(ApplicationContext context) {
		return context.getBean("generalDictAccessorJpa", GeneralDictAccessor.class);
	}
}
